import ConfigParser
import os
import re
from sets import Set   # For backward compatibility, we avoid builtin set().
import sys
import unittest
sys.path.append(os.path.abspath('..'))
from service.pconfig import PConfig
from service.rrd import Rrd
from service.exception import *

class TestConfig(unittest.TestCase):
    "Test Case for pconfig.py"
    def setUp(self):
        """Populate self.cfg from 'pluster.cfg' file."""
        if os.path.exists('pluster.cfg'):
            open('pluster.cfg', 'r')
        else:
            new_file="""
[cluster]
mail = pluster.mail@gmail.com
name = ziqiang3000
passwd = pluster.
send_to = hide1713@gmail.com,hide1713@sina.com,pluster.mail@gmail.com
smtp = smtp.gmail.com
total_node = 206

[debug]
debuglevel = 0

[logger]
file_name = ./log/msg.log
file_on = true
file_size_limit = 2000
mail_on = false
view_limit = 1000

[main_server]
address = 127.0.0.1
net = lo
port = 8888

[node]
net = lo
port = 7999

[rrd]
rrd_path = ./rrd/

[user]
root = No Description
ziqiang3000 = The Whole Cluster

[xmlrpc]
port_start = 8888
reuse = true
task_poolsize = 10"""
            open('pluster.cfg','w').write(new_file)
            
        self.cfg = PConfig()
        self.r = Rrd()

    def test_read(self):
        "Test Read some attr. Test config file is in /test dir"
        self.assert_(type(self.cfg.pool_size) is int,'wrong pool size')
        self.assert_(type(self.cfg.reuse) is bool, 'wrong config reuse')
        self.assert_(type(self.cfg.port_start) is int)
        self.assert_(type(self.cfg.dbg_level) is int )
        self.assert_(type(self.cfg.ms_port) is int )
        self.assert_(self.cfg.ms_net in ['lo','eth0','eth1'] )
        self.assert_(type(self.cfg.ms_address) is str)
        self.assert_(os.path.exists(self.cfg.rrd_path))
        self.assert_(type(self.cfg.cluster_name) is str )
        self.assert_(type(self.cfg.cluster_mail) is str )
        self.assert_(self.cfg.node_net in ['lo','eth0','eth1'])
        self.assert_(type(self.cfg.node_port) is int )
        self.assert_(self.cfg.config.has_option('user',self.cfg.cluster_name))

    def test_read_attrs(self):
        """Read attributes from pluster config file."""
        self.assertEqual(True, self.cfg.reuse)
        self.assertEqual(8888, self.cfg.ms_port)
        self.assertEqual('127.0.0.1', self.cfg.ms_address)
        self.assertTrue(re.search('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$',
                                  self.cfg.ms_address))
        self.assertTrue(re.search('^(lo|eth\d+)$', self.cfg.node_net))
        self.assertTrue(self.cfg.node_net in ['lo', 'eth0', 'eth1'])
        self.assertEqual('lo', self.cfg.node_net)
        self.assertTrue(os.path.isdir(self.cfg.rrd_path))
        self.assertTrue(self.cfg.config.has_option('user',self.cfg.cluster_name))

    def test_user2(self):
        """Add users, then read back the list of users and their attributes."""
        self.assertEqual(['root'], self.cfg.get_user_list())
        self.cfg.add_user('test', 'test user')
        # User list has two entries at this point, in an unspecified order.
        self.assertEqual(2, len(self.cfg.get_user_list()))
        self.assertTrue('root' in self.cfg.get_user_list())
        self.assertTrue('test' in self.cfg.get_user_list())
        self.assertEqual('No Description', self.cfg.read_desc('root'))
        self.assertEqual('test user',      self.cfg.read_desc('test'))
        stooges = ['larry', 'curly', 'moe']
        for user in stooges:
            self.cfg.add_user(user, 'nyuck nyuck nyuck!')
        # User list has five entries at this point, in an unspecified order.
        self.assertEqual(5, len(self.cfg.get_user_list()))
        self.assertEqual(['curly', 'larry', 'moe', 'root', 'test'],
                         sorted(self.cfg.get_user_list()))  #added in Python2.4
        self.assertEqual(Set(['root', 'test'] + stooges),
                         Set(self.cfg.get_user_list()))
        # Now leave things as we found them.
        for user in ['test'] + stooges:
            self.assertTrue(self.cfg.read_desc(user) > '')
            self.cfg.remove_user(user)
        self.assertEqual(['root'], self.cfg.get_user_list())

    def test_add_existing(self):
        """Adding an existing user simply overwrites that entry."""
        self.cfg.add_user('test', 'test user')
        self.cfg.add_user('test', 'test user')
        self.assertEqual('test user', self.cfg.read_desc('test'))
        self.cfg.add_user('test', 'test two')
        self.assertEqual('test two', self.cfg.read_desc('test'))
        self.cfg.remove_user('test')

    def test_bad_config_file(self):
        """Verify that a missing or partial config file yields an exception."""
        smallest_legal_config = """
# pconfig.py does not allow any of these values to default
[xmlrpc]
task_poolsize = 10
reuse = true
port_start = 8888

[debug]
debuglevel = 0

[main_server]
port = 8888
net = lo
address = 127.0.0.1

[rrd]
rrd_path = ./rrd/

[cluster]
name = ziqiang3000
total_node = 206
mail = hide1713@gmail.com
passwd = pluster.
smtp = smtp.gmail.com
send_to = hide1713@gmail.com, hide1713@sina.com

[logger]
file_name = ./log/msg.log
file_on = true
file_size_limit = 2000
mail_on = false
view_limit = 1000

[node]
net = lo
port = 7999
"""
        fspec = 'pluster.cfg'
        subdir = 'missing-xmlrpc-section'
        os.system('rm -rf ' + subdir)
        os.mkdir(subdir)
        os.chdir(subdir)
        self.assertRaises(IOError, PConfig)  # file not found

        open(fspec, 'w').write('')
        self.assertRaises(ConfigParser.NoSectionError, PConfig)

        open(fspec, 'w').write('[xmlrpc]')
        self.assertRaises(ConfigParser.NoOptionError, PConfig)

        open(fspec, 'w').write(smallest_legal_config)
        self.assertTrue(PConfig())   # succeeds
        self.assertEqual([], PConfig().read_user())
        cf = PConfig()
        self.assertRaises(ConfigParser.NoSectionError, cf.get_user_list)
        open(fspec, 'a').write('\n\n[user]\n')
        cf = PConfig()
        self.assertEqual([], cf.read_user())
        self.assertRaises(PConfigNoUser, cf.get_user_list)
        cf.add_user('ziqiang3000', 'The Whole Cluster')
        cf.add_user('Curly', 'nice guy')
        self.assertEqual('nice guy', cf.read_desc('Curly'))

        #remove_user and read_desc will raise PConfigNoUser
        #if user doesn't exist in user section
    
        self.assertRaises(PConfigNoUser,cf.remove_user,'foo') 
        self.assertEqual(['curly'], cf.get_user_list())
        self.assertRaises(PConfigNoUser,cf.remove_user,'nonexistant')
        self.assertRaises(PConfigNoUser,
                          cf.read_desc, 'nonexistant')
        cf.config.set('DEFAULT', 'foo', 'baz')
        cf.config.remove_section('DEFAULT')
        cf.add_node()
        # Now leave things as we found them.
        os.unlink(fspec)
        os.chdir('..')
        os.rmdir(subdir)


    def test_user (self):
        """ test user add/read"""
        self.cfg.add_user("test","test user")
        self.cfg.add_user('new','new user')
        user_list = self.cfg.get_user_list()
        for name in user_list:
            self.cfg.read_desc(name)
        self.cfg.remove_user('test')
        self.cfg.remove_user('new')



    def test_read_user (self):
        """ test read_user method"""
        self.cfg.add_user("new","new user")
        self.assertTrue(('new','new user') in self.cfg.read_user())
        self.cfg.remove_user('new')

    def test_system_integrity (self):
        """ test system integrity check"""
        self.assertEqual(['root'],self.cfg.check_rrd_exist())
        self.cfg.add_user('tom','user')
        self.assertEqual(['root','tom'],self.cfg.check_rrd_exist())
        self.cfg.remove_user('tom')
                        
        
    def test_ordered_write (self):
        """ test ordered write"""
        smallest_legal_config = """
# pconfig.py does not allow any of these values to default
[xmlrpc]
task_poolsize = 10
reuse = true
port_start = 8888

[logger]
file_name = ./log/msg.log
file_on = true
file_size_limit = 2000
mail_on = false
view_limit = 1000

[debug]
debuglevel = 0

[main_server]
port = 8888
net = lo
address = 127.0.0.1

[rrd]
rrd_path = ./rrd/

[cluster]
name = ziqiang3000
total_node = 206
mail = hide1713@gmail.com
passwd = pluster.
smtp = smtp.gmail.com
send_to = hide1713@gmail.com, hide1713@sina.com

[user]

[node]
net = lo
port = 7999
"""
        fspec = 'pluster.cfg'
        subdir = 'order'
        os.mkdir(subdir)
        os.chdir(subdir)
        #create two files and test if they are in same order
        fp=open(fspec, 'w')
        fp.write(smallest_legal_config)
        fp.close()
        cfg=PConfig()
        cfg.add_user('3','cc')
        cfg.add_user('1','aa')
        cfg.add_user('5','dd')
        cfg.add_user('2','bb')
        os.rename('pluster.cfg','pluster_old.cfg')
        fp=open(fspec, 'w')
        fp.write(smallest_legal_config)
        fp.close()
        cfg=PConfig()
        cfg.add_user('5','dd')
        cfg.add_user('2','bb')
        cfg.add_user('3','cc')
        cfg.add_user('1','aa')
        new=open('pluster.cfg','r').read()
        old=open('pluster_old.cfg','r').read()
        #new and old file should be the same
        self.assertEqual(new,old)
        os.remove('pluster.cfg')
        os.remove('pluster_old.cfg')
        os.chdir('..')
        os.rmdir(subdir)



if __name__ == '__main__':
    unittest.main()
